package com.bullardev.xldatacluster.providers;

import java.io.IOException;
import java.io.StringWriter;
import java.net.Authenticator;
import java.net.MalformedURLException;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.ws.BindingProvider;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.bullardev.xldatacluster.providers.webservice.lists.
                GetListCollectionResponse.GetListCollectionResult;
import com.bullardev.xldatacluster.providers.webservice.lists.Lists;
import com.bullardev.xldatacluster.providers.webservice.lists.ListsSoap;
import com.bullardev.xldatacluster.providers.webservice.views.
                GetViewCollectionResponse.GetViewCollectionResult;
import com.bullardev.xldatacluster.providers.webservice.views.
                                    GetViewResponse.GetViewResult;
import com.bullardev.xldatacluster.providers.webservice.views.Views;
import com.bullardev.xldatacluster.providers.webservice.views.ViewsSoap;
import com.sun.org.apache.xerces.internal.dom.ElementNSImpl;

/**
 * Class for handling metadata.
 * @author Mubin
 *
 */
public class SPMetaData {
    /**
     * URL of WSDL for Lists.
     */
    private String wsdlURL;
    /**
     * URL of WSDL for Views.
     */
    private String viewWsdlURL;
    /**
     * Username.
     */
    private String username;
    /**
     * Password.
     */
    private String password;
    /**
     * Port for View Processing.
     */
    private ViewsSoap viewPort;
    /**
     * Port for List Processing.
     */
    private ListsSoap listPort;
    /**
     * Map of column names and corresponding column labels.
     */
    private Map<String, String> columnNames;
    /**
     * Map of column names and corresponding datatypes.
     */
    private Map<String, String> columnDatatypes;
    /**
     * Map of Internal View Names and View Display Name.
     */
    private Map<String, String> viewMap = new HashMap<String, String>();
    /**
     * List Name.
     */
    private String listName;
    /**
     * View Name.
     */
    private String viewName;
    /**
     * Columns of this View.
     */
    private List<String> colsOfThisView;

    /**
     * Default view.
     */
    private String defaultView;

    /**
     * List that contains the fields of calculated types.
     */
    private List<String> calculatedTypes = new ArrayList<String>();

    /**
     * List that contains the fields of calculated types.
     */
    private List<String> percentageFields = new ArrayList<String>();

    /**
     * List that contains the fields of calculated types.
     */
    private Map<String, String> resultTypeMap = new HashMap<String, String>();

    /**
     * Constructor.
     */
    private SPMetaData() {
        //do Nothing
    }

    /**
     * Constructor.
     * @param props Connection Properties.
     */
    public SPMetaData(final Properties props) {
        this();
        //System.out.println(props);
        this.wsdlURL = props.getProperty("WSDL_URL");
        this.password = props.getProperty("PASSWORD");
        this.username = props.getProperty("USER_NAME");
        this.listName = props.getProperty("LIST_NAME");
        /*if (this.viewName == null) {
            this.viewName = "";
        }*/
        this.viewName = props.getProperty("VIEW_NAME");
        String includeHiddenFieldsStr = props.
                    getProperty("HIDDEN_FIELDS", "false");
        //System.out.println(props);
        this.viewWsdlURL = wsdlURL.substring(0, wsdlURL.lastIndexOf("/") + 1)
                            + "Views.asmx?WSDL";
        initializeListPort();
        initializeViewPort();
        getAllFieldsFromExportList();
        if (listName != null && listName.trim().length() > 0) {
            getAllViews();
        }
        /*try {
            getAllFields();
        } catch (RuntimeException e) {
            //e.printStackTrace();
            getAllFieldsFromExportList();
        }*/
        if (viewName == null || viewName.length() == 0) {
            viewName = defaultView;
         }
        getView();
    }

    /**
     * Returns the properties being used in this transaction.
     * @return Properties of connection
     */
    public final Properties getConfigProperties() {
        Properties props = new Properties();
        props.put("WSDL_URL", wsdlURL);
        props.put("USER_NAME", username);
        props.put("PASSWORD", password);
        props.put("LIST_NAME", listName != null ? listName : "");
        if (viewName == null) {
            viewName = defaultView;
        }
        props.put("VIEW_NAME", viewName != null ? viewName : "");
        return props;
    }
    /**
     * Retrieves all lists of this portal.
     * @return Map Map of all Sharepoint Lists
     */
    private Map<String, String> getAllLists() {

        //System.out.println("Getting all lists");
        Map<String, String> returnVals = new HashMap<String, String>();
        GetListCollectionResult res = listPort.getListCollection();
        Object resR = res.getContent().get(0);

        if (resR != null && resR instanceof ElementNSImpl) {
            ElementNSImpl node = (ElementNSImpl) resR;
            //Document doc = node.getOwnerDocument();
            //System.out.println(xmlToString(doc));
            NodeList nodesList = node.getElementsByTagName("List");
            //System.out.println(nodesList.getLength());
            if (nodesList.getLength() > 0) {
                for (int i = 0; i < nodesList.getLength(); i++) {
                    NamedNodeMap tempAttrib = nodesList.item(i).getAttributes();
                    String listTitle = "";
                    String listID = "";
                    for (int j = 0; j < tempAttrib.getLength(); j++) {
                        String nodeVal = tempAttrib.item(j) + "";
                        if (nodeVal.startsWith("Title=")) {
                            listTitle = nodeVal.substring(
                                    nodeVal.indexOf('=') + 2,
                                        nodeVal.length() - 1);
                        } else if (nodeVal.startsWith("ID=")) {
                            listID = nodeVal.substring(
                                    nodeVal.indexOf('=') + 2,
                                        nodeVal.length() - 1);
                        }
                        if (listTitle.length() > 0 && listID.length() > 0) {
                            break;
                        }
                    }
                    returnVals.put(listTitle, listID);
                }
            }
        }
        return returnVals;
    }

    /**
     * Retrieves a Sharepoint List of all List names.
     * @return List of Sharepoint List names
     */
    public final List<String> getAllListNames() {
        Collection<String> c = getAllLists().keySet();
        return new ArrayList<String>(c);
    }
    /**
     * Method to extract list ID from given list name.
     * @return ID of the list
     */
    private String getListID() {
        Map<String, String> map = getAllLists();
        return map.get(listName);
/*        //System.out.println("Getting ListID for: " + listName);
        GetListCollectionResult res = listPort.getListCollection();
        Object resR = res.getContent().get(0);

        if (resR != null && resR instanceof ElementNSImpl) {
            ElementNSImpl node = (ElementNSImpl) resR;
            //Document doc = node.getOwnerDocument();
            //System.out.println(xmlToString(doc));
            NodeList nodesList = node.getElementsByTagName("List");
            //System.out.println(nodesList.getLength());
            if (nodesList.getLength() > 0) {
                for (int i = 0; i < nodesList.getLength(); i++) {
                    NamedNodeMap tempAttrib = nodesList.item(i).getAttributes();
                    String listTitle = "";
                    String listID = "";
                    for (int j = 0; j < tempAttrib.getLength(); j++) {
                        String nodeVal = tempAttrib.item(j) + "";
                        //System.out.println(nodeVal);
                        if (nodeVal.startsWith("Title=")) {
                            listTitle = nodeVal.substring(
                                    nodeVal.indexOf('=') + 2,
                                        nodeVal.length() - 1);
                        } else if (nodeVal.startsWith("ID=")) {
                            listID = nodeVal.substring(
                                    nodeVal.indexOf('=') + 2,
                                        nodeVal.length() - 1);
                        }
                       // System.out.println(listTitle + " --> " + listID);
                        if (listTitle.equalsIgnoreCase(listName)
                                      &&  listID.length() > 0) {
                            //System.out.println("Returning: " + listID);
                            return listID;
                        }
                    }
                }
            }
        }
        return null;*/
    }

    /**
     * Initializes the listPort member.
     */
    private void initializeListPort() {
        Authenticator.setDefault(new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password
                        .toCharArray());
            }
        });

        try {
            Lists service = new Lists(new URL(wsdlURL));
            listPort = service.getListsSoap();
            ((BindingProvider) listPort).getRequestContext().put(
                    BindingProvider.USERNAME_PROPERTY, username);
            ((BindingProvider) listPort).getRequestContext().put(
                    BindingProvider.PASSWORD_PROPERTY, password);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Initializes the viewPort member.
     * @return
     */
    private void initializeViewPort() {

        Views view = null;
        Authenticator.setDefault(new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password
                        .toCharArray());
            }
        });
        try {
            view = new Views(new URL(viewWsdlURL));
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        }

        viewPort = view.getViewsSoap();
        ((BindingProvider) viewPort).getRequestContext().put(
                BindingProvider.USERNAME_PROPERTY, username);
        ((BindingProvider) viewPort).getRequestContext().put(
                BindingProvider.PASSWORD_PROPERTY, password);

    }

    /**
     * Retrieves all view names for a given list.
     * @param thisListName Name of the list
     * @return Map of view name and displayName
     */
    public final Map<String, String> getAllViewsForList(
                                final String thisListName) {
        String temp  = listName;
        listName = thisListName;
        Map<String, String> tempViews = viewMap;
        viewMap.clear();
        getAllViews();
        if (temp != null) {
            listName = temp;
        }
        if (tempViews != null) {
            viewMap = tempViews;
        }
        return viewMap;
    }
    /**
     * Retrieve All views for this list.
     * Populates the viewMap
     */
    private void getAllViews() {
        //System.out.println("GetAllViews....." + listName);
        GetViewCollectionResult allViews = viewPort.getViewCollection(listName);
        Object allViewsResult = allViews.getContent().get(0);
        if (allViewsResult instanceof ElementNSImpl) {
            ElementNSImpl res = (ElementNSImpl) allViewsResult;
            Document doc = res.getOwnerDocument();
            //System.out.println("View " + xmlToString(doc));
            NodeList attributeTags = doc.getElementsByTagName("View");
            for (int j = 0; j < attributeTags.getLength(); j++) {
                NamedNodeMap attribs = attributeTags.item(j).getAttributes();
                String displayName = "";
                boolean isDefaultView = false;
                for (int i = 0; i < attribs.getLength(); i++) {
                    String nodeVal = attribs.item(i) + "";
                    if (nodeVal.startsWith("DisplayName=")) {
                       displayName = nodeVal.substring(nodeVal.indexOf('=') + 2,
                                nodeVal.length() - 1);
                        viewMap.put(displayName, "");
                    } else if (nodeVal.startsWith("Name=")) {
                       viewMap.put(displayName, (nodeVal.substring(nodeVal.
                               indexOf('=') + 2, nodeVal.length() - 1)));
                       //System.out.println("ViewName: "+displayName);
                       if (isDefaultView) {
                           //System.out.println("is default view");
                           defaultView = displayName;
                       }
                    } else if (nodeVal.startsWith("DefaultView=")) {
                        String val =  (nodeVal.substring(nodeVal.
                                indexOf('=') + 2, nodeVal.length() - 1));
                        if ("true".equalsIgnoreCase(val)) {
                            //System.out.println("is default view");
                            isDefaultView = true;
                        }
                     }
                }
            }
        }
        //System.out.println(viewMap);
    }

    /**
     * Retrieves the metadata of given view for this list.
     */
    private void getView() {
        String viewGUID = "";
        //System.out.println("ViewName.." + viewName);
        //System.out.println("viewmap now.. " + viewMap);
        if (viewName != null && viewName.length() > 0
                    && viewMap.get(viewName) != null) {
            viewGUID = (String) viewMap.get(viewName);
        } else {
            //System.out.println("didn't get view guid");
            return;
        }
        GetViewResult result = viewPort.getView(listName, viewGUID);
        Object viewResult = result.getContent().get(0);
        if (viewResult instanceof ElementNSImpl) {
            ElementNSImpl res = (ElementNSImpl) viewResult;
            Document doc = res.getOwnerDocument();
            //System.out.println("View Data: \n" + xmlToString(doc));
            NodeList attributeTags = doc.getElementsByTagName("FieldRef");

            colsOfThisView = new ArrayList<String>();
            for (int j = 0; j < attributeTags.getLength(); j++) {
                NamedNodeMap attribs = attributeTags.item(j).getAttributes();
                for (int i = 0; i < attribs.getLength(); i++) {
                    String nodeVal = attribs.item(i) + "";
                    if (nodeVal.startsWith("Name=")) {
                       colsOfThisView.add(nodeVal.substring(
                                   nodeVal.indexOf('=') + 2,
                                        nodeVal.length() - 1));
                    }
                }
            }
        }
    }

    /**
     * Retrieves all the fields MetaData from ExportList.
     */

    private void getAllFieldsFromExportList() {
        Authenticator.setDefault(new Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(
                        username, password.toCharArray());
            }
        });

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = null;
        try {
            docBuilder = dbf.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }
        String prefix = wsdlURL.substring(0, wsdlURL.lastIndexOf('/') + 1);

        Document doc = null;
        try {
            String listID = getListID();
            if (listID == null) {
                return;
            }
            doc = docBuilder.parse(prefix + "owssvr.dll?"
                    + "Cmd=ExportList&"
                    + "List=" + listID);
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        //System.out.println("From ExportList: \n" + xmlToString(doc));
        NodeList attributeTags = doc.getElementsByTagName("Field");
        List<String> tempColNames = new ArrayList<String>();
        List<String> tempDataTypes = new ArrayList<String>();
        List<String> tempColLabels = new ArrayList<String>();

        for (int j = 0; j < attributeTags.getLength(); j++) {
            NamedNodeMap attribs = attributeTags.item(j).getAttributes();
            String colName = "";
            String colDispName = "";
            String colType = "";
            String resultType = "";
            boolean isPercentage = false;
            for (int i = 0; i < attribs.getLength(); i++) {
                String nodeVal = attribs.item(i) + "";
                //System.out.println(nodeVal);
                if (nodeVal.startsWith("Name=")) {
                   colName = nodeVal.substring(nodeVal.indexOf('=') + 2,
                                                         nodeVal.length() - 1);
                } else if (nodeVal.startsWith("DisplayName=")) {
                   colDispName = nodeVal.substring(nodeVal.indexOf('=') + 2,
                            nodeVal.length() - 1);
                } else if (nodeVal.startsWith("Type=")) {
                   colType = nodeVal.substring(nodeVal.indexOf('=') + 2,
                            nodeVal.length() - 1);
                } else if (nodeVal.startsWith("ResultType=")) {
                   resultType = nodeVal.substring(nodeVal.indexOf('=') + 2,
                            nodeVal.length() - 1);
                } else if (nodeVal.startsWith("Percentage=")) {
                   String temp = nodeVal.substring(nodeVal.indexOf('=') + 2,
                            nodeVal.length() - 1);
                   if ("TRUE".equalsIgnoreCase(temp)) {
                       isPercentage = true;
                   }
                }
            }
            if (colName.length() > 0  && colDispName.length() > 0
                    && colType.length() > 0) {
                tempColLabels.add(colDispName);
                tempColNames.add(colName);
                tempDataTypes.add(colType);
            }
            if (isPercentage) {
                percentageFields.add(colName);
            }
            if (resultType.length() > 0
                    && colType.equalsIgnoreCase("Calculated")) {
                calculatedTypes.add(colName);
                resultTypeMap.put(colName, resultType);
            }
        }

        columnDatatypes = new HashMap<String, String>();
        columnNames = new HashMap<String, String>();
        for (Iterator<String> itr1 = tempDataTypes.iterator(),
              itr2 = tempColNames.iterator(), itr3 = tempColLabels.iterator();
                         itr1.hasNext() && itr2.hasNext() && itr3.hasNext();) {
            String colName = itr2.next();
            String dataType = itr1.next();
            String colLabel = itr3.next();
            columnDatatypes.put(colName, dataType);
            columnNames.put(colName, colLabel);
        }
        //System.out.println("Calculated types: "+calculatedTypes);
    }

    /**
     * Retrieves all the fields metadata for this list.
     *
     */
    public final void getAllFields() {



        Authenticator.setDefault(new Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(
                        username, password.toCharArray());
            }
        });

        String listID = getListID();
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = null;
        try {
            docBuilder = dbf.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        }
        String prefix = wsdlURL.substring(0, wsdlURL.lastIndexOf('/') + 1);
        String suffix = "&XMLDATA=TRUE";
        if ("Tasks".equalsIgnoreCase(listName)) {
            suffix = "&Query=*&XMLDATA=TRUE";
        }
        Document doc = null;
        try {
            doc = docBuilder.parse(prefix + "owssvr.dll?"
                    + "Cmd=Display&"
                    + "List=" + listID + suffix);
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //System.out.println("Meta Data: "+xmlToString(doc));
        NodeList attributeTags = doc.getElementsByTagName("s:AttributeType");
        List<String> tempColNames = new ArrayList<String>();
        List<String> tempDataTypes = new ArrayList<String>();
        List<String> tempColLabels = new ArrayList<String>();

        for (int j = 0; j < attributeTags.getLength(); j++) {
            NamedNodeMap attribs = attributeTags.item(j).getAttributes();
            for (int i = 0; i < attribs.getLength(); i++) {
                String nodeVal = attribs.item(i) + "";
                if (nodeVal.startsWith("name=")) {
                    tempColNames.add(nodeVal.substring(nodeVal.indexOf('=') + 2,
                                                         nodeVal.length() - 1));
                } else if (nodeVal.startsWith("rs:name=")) {
                   tempColLabels.add(nodeVal.substring(nodeVal.indexOf('=') + 2,
                            nodeVal.length() - 1));
                }
            }
        }
        NodeList dataTypeTags = doc.getElementsByTagName("s:datatype");
        for (int j = 0; j < attributeTags.getLength(); j++) {
            NamedNodeMap dataTypes = dataTypeTags.item(j).getAttributes();
            for (int i = 0; i < dataTypes.getLength(); i++) {
                String dataTypesAttribs = dataTypes.item(i) + "";
                if (dataTypesAttribs.startsWith("dt:type=")) {
                    tempDataTypes.add(dataTypesAttribs.substring(
                                    dataTypesAttribs.indexOf('=') + 2,
                                        dataTypesAttribs.length() - 1));
                }
            }
        }

        columnDatatypes = new HashMap<String, String>();
        columnNames = new HashMap<String, String>();
        for (Iterator<String> itr1 = tempDataTypes.iterator(),
              itr2 = tempColNames.iterator(), itr3 = tempColLabels.iterator();
                         itr1.hasNext() && itr2.hasNext() && itr3.hasNext();) {
            String colName = itr2.next();
            String dataType = itr1.next();
            String colLabel = itr3.next();
            columnDatatypes.put(colName, dataType);
            columnNames.put(colName, colLabel);
        }
    }

    /**
     * Getter for colsOfThisView.
     * @return List list of columns in this view
     */
    public final List<String> getColumnNames() {
        return colsOfThisView;
    }

    /**
     * Getter for columnDataTypes.
     * @return Map Map of column name and column data type
     */
    public final Map<String, String> getDataTypesMap() {
        return columnDatatypes;
    }

    /**
     * Retrieves data types from map.
     * @return List list of datatypes
     */
    public final List<String> getDataTypes() {
        List<String> result = new ArrayList<String>();
        for (Iterator<String> iterator = getColumnNames().iterator();
                                        iterator.hasNext();) {
            String colName = (String) iterator.next();
            result.add(columnDatatypes.get(colName));
        }
        return result;
    }
    /**
     * Getter for columnNames.
     * @return Map Map of column name and column label
     */
    public final Map<String, String> getColumnLabelsMap() {
        return columnNames;
    }

    /**
     * Retrieves the names of the columns from columnNames Map.
     * @return List List of column names
     */
    public final List<String> getColumnLabels() {
        List<String> result = new ArrayList<String>();
        //System.out.println("Cols of this view: " + colsOfThisView);
        for (Iterator<String> iterator = colsOfThisView.iterator();
                                                iterator.hasNext();) {
            String key = (String) iterator.next();
            result.add(columnNames.get(key));
        }
        return result;
    }
    /**
     * Main method for testing.
     * @param args Command line arguments.
     */
    public static void main(final String[] args) {
        Properties connectionProps = new Properties();
        connectionProps.put("WSDL_URL",
                "http://localhost/_vti_bin/Lists.asmx?WSDL");
        connectionProps.put("WSDL_URL",
                "http://sp.demo.bullardev.com/_vti_bin/Lists.asmx?WSDL");
        connectionProps.put("USER_NAME", "ibm");
        connectionProps.put("USER_NAME", "Yousuf");
        connectionProps.put("PASSWORD", "welcome2ibm");
        connectionProps.put("PASSWORD", "letmein");
        connectionProps.put("LIST_NAME", "MyTestList");
        connectionProps.put("LIST_NAME", "Test List 1");

        SPMetaData md = new SPMetaData(connectionProps);
        //System.out.println(md.getListID());
        md.getAllViews();
        System.out.println("Column Names: " + md.getColumnNames());
        System.out.println("Column Labels: " + md.getColumnLabels());
        System.out.println("Datatypes map: " + md.getDataTypesMap());
        System.out.println("Datatypes: " + md.getDataTypes());
        //md.getAllFields();
    }

    /**
     * Processes the XML.
     * @param docToString XML Document to be displayed
     * @return String representation of XML Document
     */
        @SuppressWarnings("unused")
        private String xmlToString(final Document docToString) {
        String returnString = "\n-------------- XML START --------------\n";
        try {
            //create string from xml tree
            //Output the XML
            //set up a transformer
            TransformerFactory transfac = TransformerFactory.newInstance();
            Transformer trans;
            trans = transfac.newTransformer();
            trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            trans.setOutputProperty(OutputKeys.INDENT, "yes");
            StringWriter sw = new StringWriter();
            StreamResult streamResult = new StreamResult(sw);
            DOMSource source = new DOMSource(docToString);
            trans.transform(source, streamResult);
            String xmlString = sw.toString();
            //print the XML
            returnString = returnString + xmlString;
        } catch (TransformerException ex) {
            ex.printStackTrace();
        }
        returnString = returnString + "-------------- XML END --------------";
        return returnString;
    }
    /**
     * @return the defaultView
     */
    public final String getDefaultView() {
        return defaultView;
    }

    /**
     * Determines if the column in of type calculated.
     * @param colName Name of the column
     * @return true if it is a calculated type, otherwise false
     */
    public final boolean isCalculated(final String colName) {
        if (calculatedTypes.contains(colName)) {
            return true;
        }
        return false;
    }

    /**
     * Determines if the column in of type percentage.
     * @param colName Name of the column
     * @return true if it is a percentage type, otherwise false
     */
    public final boolean isPercentage(final String colName) {
        if (percentageFields.contains(colName)) {
            return true;
        }
        return false;
    }

    /**
     * Returns the result type of this column.
     * @param colName Name of the column
     * @return Result type of given column.
     */
    public final String getResultType(final String colName) {
        return resultTypeMap.get(colName);
    }
}
